/*
 * Copyright Thoughtworks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { SparkRoutes } from "helpers/spark_routes";
import { i18n } from "helpers/i18n";
import m from "mithril";
import Stream from "mithril/stream";
import { FlashMessage, MessageType } from "views/components/flash_message";
import { FlashMessageModelWithTimeout } from "views/components/flash_message";
import { HeaderPanel } from "views/components/header_panel";

import { Page, PageState } from "views/pages/page";
import { AdminConfigXmlWidget } from "views/pages/admin_config_xml/admin_config_xml_widget";

interface State {
  onError: (msg: m.Children) => void;
  onSuccessfulSave: (msg: m.Children) => void;
  configXml: Stream<string>;
  configLocation: Stream<string>;
  lastModifiedBy: Stream<string>;
  lastModifiedAt: Stream<string>;
  md5: Stream<string>;
  isEditing: Stream<boolean>;
  editedConfigXml: Stream<string>;
}

export class AdminConfigXMLPage extends Page<null, State> {
  protected flashMessage: FlashMessageModelWithTimeout = new FlashMessageModelWithTimeout();
  protected pageState: PageState = PageState.LOADING;

  oninit(vnode: m.Vnode<null, State>) {
    super.oninit(vnode);
    this.flashMessage = new FlashMessageModelWithTimeout();

    // Load page-specific translations
    i18n.loadPageTranslations("admin-config-xml");

    vnode.state.configXml = Stream("");
    vnode.state.configLocation = Stream("");
    vnode.state.lastModifiedBy = Stream("");
    vnode.state.lastModifiedAt = Stream("");
    vnode.state.md5 = Stream("");
    vnode.state.isEditing = Stream(false);
    vnode.state.editedConfigXml = Stream("");

    vnode.state.onError = (msg: m.Children) => {
      this.flashMessage.setMessage(MessageType.alert, msg);
    };

    vnode.state.onSuccessfulSave = (msg: m.Children) => {
      this.flashMessage.setMessage(MessageType.success, msg);
    };

    // 检查初始路由状态
    const initialRoute = m.route.get();

    // 如果初始路由是编辑路由，设置编辑状态
    if (initialRoute === "/edit") {
      vnode.state.isEditing(true);
    }

    this.fetchData(vnode);
  }

  onupdate(vnode: m.Vnode<null, State>) {
    // 检查路由片段变化
    const currentRoute = m.route.get();
    const isEditRoute = currentRoute === "/edit";

    if (isEditRoute && !vnode.state.isEditing()) {
      // 切换到编辑模式
      vnode.state.isEditing(true);
      vnode.state.editedConfigXml(vnode.state.configXml());
      m.redraw();
    } else if (!isEditRoute && vnode.state.isEditing()) {
      // 切换回查看模式
      vnode.state.isEditing(false);
      m.redraw();
    }
  }

  componentToDisplay(vnode: m.Vnode<null, State>): m.Children {
    if (this.pageState === PageState.LOADING) {
      return (
        <div>
          <FlashMessage type={MessageType.info}>
            {i18n.tSyncForPage("admin.config_xml.loading.configuration", "admin-config-xml")}
          </FlashMessage>
        </div>
      );
    }

    return (
      <div>
        <FlashMessage type={this.flashMessage.type} message={this.flashMessage.message} />
        <AdminConfigXmlWidget
          configContent={vnode.state.configXml()}
          configLocation={vnode.state.configLocation()}
          lastModifiedBy={vnode.state.lastModifiedBy()}
          lastModifiedAt={vnode.state.lastModifiedAt()}
          onEdit={() => this.handleEdit()}
          isEditing={vnode.state.isEditing()}
          editedConfigXml={vnode.state.editedConfigXml}
          onCancel={() => this.handleCancel(vnode)}
          onSave={() => this.handleSave(vnode)}
          onContentChange={(content: string) => vnode.state.editedConfigXml(content)}
        />
      </div>
    );
  }

  pageName(): string {
    return i18n.tSyncForPage("admin.config_xml.title", "admin-config-xml");
  }

  private handleEdit(): void {
    // 跳转到编辑模式 - 使用正确的Mithril hash路由格式
    const editRoute = "/edit";
    m.route.set(editRoute);

    // 重新获取数据以确保编辑状态下有最新内容
    // 注意：这里不需要立即调用fetchData，因为onupdate会处理状态切换
  }

  private handleCancel(vnode: m.Vnode<null, State>): void {
    // 检查是否有未保存的更改
    if (vnode.state.editedConfigXml() !== vnode.state.configXml()) {
      if (confirm(i18n.tSyncForPage("admin.config_xml.discard.changes.confirm", "admin-config-xml"))) {
        vnode.state.isEditing(false);
        vnode.state.editedConfigXml(vnode.state.configXml());
        m.route.set("/");
      }
    } else {
      vnode.state.isEditing(false);
      m.route.set("/");
    }
  }

  private handleSave(vnode: m.Vnode<null, State>): Promise<any> {
    const payload = new URLSearchParams();
    payload.append("xmlFile", vnode.state.editedConfigXml());
    payload.append("md5", vnode.state.md5());

    // 检查是否需要添加确认头
    const headers: { [key: string]: string } = {
      "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
      "X-Cruise-Config-MD5": vnode.state.md5(),
    };

    // 如果需要添加确认头，根据API安全模式确定
    // 这里我们简单地添加它，因为在SPA中很难确定服务器端的模式
    headers["X-GoCD-Confirm"] = "true";

    return m
      .request({
        method: "POST",
        url: SparkRoutes.adminConfigXmlPath(),
        headers: headers,
        body: payload,
        deserialize: (value) => value,
      })
      .then((response: any) => {
        // 保存成功
        vnode.state.configXml(vnode.state.editedConfigXml());
        vnode.state.isEditing(false);
        this.flashMessage.setMessage(
          MessageType.success,
          i18n.tSyncForPage("admin.config_xml.save.success", "admin-config-xml")
        );
        m.route.set("/");

        // 重新加载数据以获取新的MD5
        this.fetchData(vnode);
      })
      .catch((error: any) => {
        // 处理错误
        let errorMessage = i18n.tSyncForPage("admin.config_xml.save.error", "admin-config-xml");
        if (error && error.responseText) {
          try {
            const errorResponse = JSON.parse(error.responseText);
            if (errorResponse.result) {
              errorMessage = errorResponse.result;
            }
          } catch (e) {
            // 如果无法解析JSON，使用默认错误消息
          }
        }
        this.flashMessage.setMessage(MessageType.alert, errorMessage);
      });
  }

  fetchData(vnode: m.Vnode<null, State>): Promise<any> {
    this.pageState = PageState.LOADING;

    return m
      .request({
        method: "GET",
        url: SparkRoutes.adminConfigXmlPath(),
        headers: {
          Accept: "text/xml",
        },
        extract: (xhr) => {
          // 从响应头中提取MD5和其他信息
          const md5 = xhr.getResponseHeader("X-CRUISE-CONFIG-MD5") || "";
          return {
            xml: xhr.responseText,
            md5: md5,
            status: xhr.status,
          };
        },
      })
      .then((result: any) => {
        // 直接使用原始XML
        vnode.state.configXml(result.xml);
        vnode.state.md5(result.md5);

        // TODO: 设置其他默认值（目前API不提供这些信息）
        vnode.state.configLocation("config/cruise-config.xml"); // 默认位置
        vnode.state.lastModifiedBy(i18n.tSyncForPage("admin.config_xml.system", "admin-config-xml")); // 默认值
        vnode.state.lastModifiedAt(i18n.tSyncForPage("admin.config_xml.recently", "admin-config-xml")); // 默认值

        // 检查当前路由是否为编辑模式
        const currentRoute = m.route.get();
        const isEditRoute = currentRoute === "/edit";
        vnode.state.isEditing(isEditRoute);
        vnode.state.editedConfigXml(result.xml);

        this.pageState = PageState.OK;
        m.redraw();
      })
      .catch((error) => {
        this.flashMessage.setMessage(
          MessageType.alert,
          i18n.tSyncForPage("admin.config_xml.error.fetching.config", "admin-config-xml")
        );
        this.pageState = PageState.FAILED;
        m.redraw();
      });
  }

  helpText(): m.Children {
    return <span>{i18n.tSyncForPage("admin.config_xml.help.text", "admin-config-xml")}</span>;
  }

  protected headerPanel(vnode: m.Vnode<null, State>): any {
    return <HeaderPanel title={this.pageName()} help={this.helpText()} />;
  }

  // 注释掉格式化函数，当前直接使用原始XML
  // private formatXml(xml: string): string {
  //   // 使用基本的换行格式化
  //   return xml.replace(/></g, '>\n<');
  // }
}
